#include <iostream>
#include <cstdlib>
#include <omp.h>
#include <sys/time.h>
#include <cstring>
#include "loader.h"
#include "parser.h"
#include "palins.h"
#include "Crivo.h"
using namespace std;

/*
 * Se definimo o programa eh compilado utilizando a biblioteca
 * 	openMP
 */
#define _USING_MP

/*
 * Ponteiro para objeto da classe 'Loader'
 */
Loader *loader;

/*
 * Ponteiro para objeto da classe 'Parser'
 */
Parser *parser;

/*
 * Ponteiro para objeto da classe 'Palins'
 */
Palins *palins;

/*
 * Ponteiro para uma string que recebera os blocos lidos do arquivo
 * 	de entrada
 */
string *inputData;

/*
 * Vetor de strings que contera as palavras palindromos
 */
vector<string> *palins_words;

/*
 * Vetor de strings que contera as frases palindromos
 */
vector<string> *palins_phrases;

/*
 * Vetor de strings que recebera as palavras depois que o parser eh
 * 	executado em cada um dos blocos lidos
 */
vector<string> *words;

/*
 * Vetor de strings que recebera as frases depois que o parser eh
 * 	executado em cada um dos blocos lidos
 */
vector<string> *phrases;

/* Vetor de strings que recebera a soma ASCII de cada uma das palavras
 * 	do vetor 'words'
 */
vector<string> *p_asciisum;

/*
 * Vetor de strings que recebera a soma ASCII de cada uma das frases
 * 	do vetor 'phrases'
 */
vector<string> *w_asciisum;

/*
 * Ponteiro para objeto da classe 'Crivo'
 */
Crivo *eratosthenes;

/* Variaveis que irao armazenar o numero total de frases, palavras e primos
 * 	encontrados
 */
int palindromePTotal = 0, palindromeWTotal = 0, primeTotal = 0;

/* Variaveis que irao receber o tamanho total do arquivo de entrada
 * 	e o que ja foi lido
 */
int readed = 0, length;

int main(int argc, char *argv[])
{
	struct timeval start, end; /* Variaveis para guardar o tempo de execucao */
	int time;

	if (argc < 3) {
		cout << "Uso: " << argv[0] << " <input> <modo: 1-Palavras palindromos 2-Palavras e frases palindromos> [opcoes]" << endl;
		cout << endl << "Opcoes:" << endl;
		cout << "   -q [QUIET]	Imprime apenas os resultados, sem as listas de palindromos" << endl << endl;
		return EXIT_FAILURE;
	}

	short mode = atoi(argv[2]);
	
	loader = new Loader(argv[1]);

	parser = new Parser();

	palins = new Palins();

	palins_words = new vector<string>;

	palins_phrases = new vector<string>;

	p_asciisum = new vector<string>;

	w_asciisum = new vector<string>;

	eratosthenes = new Crivo();

	length = loader->tellLength();

	gettimeofday(&start, NULL);

	while (readed < length) {
#ifdef _USING_MP
	/* Modo paralelo */
		#pragma omp parallel sections num_threads(2)
		{
#endif

#ifdef _USING_MP
		#pragma omp section
#endif
			{
				if (readed + BLOCK_SIZE < length)
					readed += loader->readBlock(mode);
				else
					readed += loader->readBlock(mode, length - readed);
			}
#ifdef _USING_MP
		#pragma omp section
#endif
			{

				parser->splitBlock(inputData, mode);

				palins->checkPalins(*parser, mode);

				delete inputData;
			}

		}
	}

	gettimeofday(&end, NULL);
	time = end.tv_sec - start.tv_sec;

	cout << endl;
		cout << "======================================================" << endl;
		cout << "================= PALAVRAS PALINDROMAS ===============" << endl;
		cout << "======================================================" << endl << endl;;

		vector<string>::iterator i = palins_words->begin();
		vector<string>::iterator j = w_asciisum->begin();
		while (i != palins_words->end()) {
			cout << *i << "   " << *j << endl;
			i++;
			j++;
		}
		cout << endl;

		if (mode == WORDS_PHRASES) {
			cout << endl << "======================================================" << endl;
			cout << "================= FRASES PALINDROMAS =================" << endl;
			cout << "======================================================" << endl << endl;

			vector<string>::iterator i = palins_phrases->begin();
			vector<string>::iterator j = p_asciisum->begin();
			while (i != palins_phrases->end()) {
				cout << *i << "   " << *j << endl;
				i++;
				j++;
			}
			cout << endl << endl << "=======================================================" << endl;
		}
		cout << endl;

	cout << "TEMPO DE EXECUCAO: " << time << endl;
	cout << "PALAVRAS PALINDROMAS ENCONTRADAS: " << palindromeWTotal << endl;
	if (mode == WORDS_PHRASES)
		cout << "FRASES PALINDROMAS ENCONTRADAS: " << palindromePTotal << endl;
	cout << "TOTAL DE NUMEROS PRIMOS: " << primeTotal << endl;
	cout << endl;
}
